package com.lew.jlight.web.shiro.config;

import com.google.common.base.Preconditions;
import com.google.common.collect.Maps;

import com.lew.jlight.web.service.LoginService;
import com.lew.jlight.web.service.RoleService;
import com.lew.jlight.web.service.UserRoleService;
import com.lew.jlight.web.shiro.UserRealm;
import com.lew.jlight.web.shiro.filter.FormLoginFilter;
import com.lew.jlight.web.shiro.filter.ResourceCheckFilter;
import com.lew.jlight.web.shiro.permission.UrlPermissionResolver;
import com.lew.jlight.web.shiro.session.cache.ShiroCacheManager;
import com.lew.jlight.web.shiro.session.dao.RedisSessionDao;

import org.apache.shiro.cache.CacheManager;
import org.apache.shiro.cache.ehcache.EhCacheManager;
import org.apache.shiro.codec.Base64;
import org.apache.shiro.session.mgt.SessionManager;
import org.apache.shiro.session.mgt.eis.MemorySessionDAO;
import org.apache.shiro.session.mgt.eis.SessionDAO;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.CookieRememberMeManager;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.servlet.SimpleCookie;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.DelegatingFilterProxy;

import java.util.Map;

import javax.annotation.Resource;
import javax.servlet.DispatcherType;
import javax.servlet.Filter;

import at.pollux.thymeleaf.shiro.dialect.ShiroDialect;


@Configuration
public class ShiroConfig {

    @Resource
    private RoleService roleService;

    @Resource
    private UserRoleService userRoleService;

    @Resource
    private LoginService loginService;

    @Resource
    private Environment environment;

    @Bean
    public FilterRegistrationBean filterRegistrationBean() {
        FilterRegistrationBean filterRegistration = new FilterRegistrationBean();
        filterRegistration.setFilter(new DelegatingFilterProxy("shiroFilter"));
        filterRegistration.setEnabled(false);
        filterRegistration.addUrlPatterns("/*");
        filterRegistration.setDispatcherTypes(DispatcherType.REQUEST, DispatcherType.FORWARD);
        return filterRegistration;
    }

    @Bean
    public DefaultAdvisorAutoProxyCreator getDefaultAdvisorAutoProxyCreator() {
        DefaultAdvisorAutoProxyCreator daap = new DefaultAdvisorAutoProxyCreator();
        daap.setProxyTargetClass(true);
        return daap;
    }

    @Bean("shiroFilter")
    public ShiroFilterFactoryBean shiroFilter() {
        ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
        bean.setSecurityManager(securityManager());
        bean.setLoginUrl("/login");
        bean.setSuccessUrl("/index");
        bean.setUnauthorizedUrl("/unauthor");

        ResourceCheckFilter resourceCheckFilter = new ResourceCheckFilter();
        resourceCheckFilter.setErrorUrl("/403.html");
        FormLoginFilter formLoginFilter = new FormLoginFilter();
        formLoginFilter.setLoginService(loginService);
        formLoginFilter.setRoleService(roleService);
        formLoginFilter.setUserRoleService(userRoleService);

        Map<String, Filter> filters = Maps.newLinkedHashMap();
        filters.put("formLoginFilter", formLoginFilter);
        filters.put("resourceCheckFilter", resourceCheckFilter);
        bean.setFilters(filters);

        Map<String, String> chains = Maps.newLinkedHashMap();
        String anonUrls = environment.getProperty("shiro.anon.urls");
        Preconditions.checkArgument(!StringUtils.isEmpty(anonUrls), "annoUrl must not be empty");
        String[] anonArray = anonUrls.split(",");
        for (String anonUrl : anonArray) {
            chains.put(anonUrl, "anon");
        }
        chains.put("/**", "formLoginFilter,resourceCheckFilter");
        bean.setFilterChainDefinitionMap(chains);
        return bean;
    }

    @Bean
    public CacheManager cacheManager() {
        String cacheType = environment.getProperty("shiro.cache.type");
        if ("redis".equals(cacheType)) {
            return new ShiroCacheManager();
        } else {
            EhCacheManager cacheManager = new EhCacheManager();
            cacheManager.setCacheManagerConfigFile("classpath:ehcache-shiro.xml");
            return cacheManager;
        }
    }

    @Bean
    public SessionDAO getSessionDao() {
        String cacheType = environment.getProperty("shiro.cache.type");
        if ("redis".equals(cacheType)) {
            return new RedisSessionDao();
        }
        return new MemorySessionDAO();
    }


    @Bean(name = "securityManager")
    public DefaultWebSecurityManager securityManager() {
        DefaultWebSecurityManager manager = new DefaultWebSecurityManager();
        manager.setRealm(userRealm());
        manager.setSessionManager(sessionManager());
        manager.setCacheManager(cacheManager());
        manager.setRememberMeManager(rememberMeManager());
        return manager;
    }

    @Bean
    public SessionManager sessionManager() {
        DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
        String sessionTimeout = environment.getProperty("shiro.session.timeout");
        sessionManager.setGlobalSessionTimeout(Long.valueOf(sessionTimeout));
        sessionManager.setDeleteInvalidSessions(true);
        //设置sessionDao
        sessionManager.setSessionDAO(getSessionDao());
        sessionManager.setSessionValidationSchedulerEnabled(true);
        return sessionManager;
    }

    @Bean
    public UserRealm userRealm() {
        UserRealm userRealm = new UserRealm();
        String isCacheEnabled = environment.getProperty("shiro.authorization.cache.enabled");
        userRealm.setAuthorizationCachingEnabled(Boolean.valueOf(isCacheEnabled));
        userRealm.setPermissionResolver(urlPermissionResolver());
        return userRealm;
    }


    @Bean
    public UrlPermissionResolver urlPermissionResolver() {
        return new UrlPermissionResolver();
    }

    @Bean
    public ShiroDialect shiroDialect() {
        return new ShiroDialect();
    }


    @Bean
    public SimpleCookie rememberMeCookie() {
        String cookieTimeout = environment.getProperty("shiro.cookie.timeout");
        SimpleCookie simpleCookie = new SimpleCookie("rememberMe");
        simpleCookie.setMaxAge(Integer.valueOf(cookieTimeout));
        return simpleCookie;
    }

    @Bean
    public CookieRememberMeManager rememberMeManager() {
        CookieRememberMeManager cookieRememberMeManager = new CookieRememberMeManager();
        cookieRememberMeManager.setCookie(rememberMeCookie());
        String secretKey = environment.getProperty("shiro.secret.key");
        cookieRememberMeManager.setCipherKey(Base64.decode(secretKey));
        return cookieRememberMeManager;
    }

   /* //若返回会导致注解事务失效
    @Bean
    public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
        return new LifecycleBeanPostProcessor();
    }*/
}
